<!DOCTYPE html>
<html lang="zh-CN">
<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>语音识别测试</title>
    <style>
        body {
            font-family: Arial, sans-serif;
            max-width: 800px;
            margin: 0 auto;
            padding: 20px;
            background-color: #f5f5f5;
        }
        .card {
            background: white;
            border-radius: 8px;
            padding: 20px;
            margin-bottom: 20px;
            box-shadow: 0 2px 4px rgba(0,0,0,0.1);
        }
        .status {
            padding: 10px;
            border-radius: 4px;
            margin: 10px 0;
        }
        .status.success { background-color: #d4edda; color: #155724; }
        .status.error { background-color: #f8d7da; color: #721c24; }
        .status.info { background-color: #d1ecf1; color: #0c5460; }
        .btn {
            background: #007bff;
            color: white;
            border: none;
            padding: 10px 20px;
            border-radius: 4px;
            cursor: pointer;
            margin: 5px;
        }
        .btn:hover { background: #0056b3; }
        .btn:disabled { background: #6c757d; cursor: not-allowed; }
        .btn.danger { background: #dc3545; }
        .btn.danger:hover { background: #c82333; }
        .btn.success { background: #28a745; }
        .btn.success:hover { background: #218838; }
        .log {
            background: #f8f9fa;
            border: 1px solid #dee2e6;
            border-radius: 4px;
            padding: 10px;
            max-height: 300px;
            overflow-y: auto;
            font-family: monospace;
            font-size: 12px;
        }
        .input-group {
            margin: 10px 0;
        }
        .input-group label {
            display: block;
            margin-bottom: 5px;
            font-weight: bold;
        }
        .input-group input, .input-group select {
            width: 100%;
            padding: 8px;
            border: 1px solid #ddd;
            border-radius: 4px;
        }
        .recording {
            animation: pulse 1s infinite;
        }
        @keyframes pulse {
            0% { opacity: 1; }
            50% { opacity: 0.5; }
            100% { opacity: 1; }
        }
    </style>
</head>
<body>
    <h1>🎤 语音识别测试页面</h1>
    
    <div class="card">
        <h2>连接状态</h2>
        <div id="connectionStatus" class="status info">正在连接...</div>
        <div id="deviceInfo" class="status info">设备信息加载中...</div>
        <button id="connectBtn" class="btn">连接服务器</button>
        <button id="disconnectBtn" class="btn danger">断开连接</button>
    </div>

    <div class="card">
        <h2>语音识别测试</h2>
        <div class="input-group">
            <label>识别模式:</label>
            <select id="recognitionMode">
                <option value="server">服务端识别</option>
                <option value="client">客户端识别</option>
            </select>
        </div>
        <div class="input-group">
            <label>语言:</label>
            <select id="language">
                <option value="zh-CN">中文</option>
                <option value="en-US">英文</option>
                <option value="ja-JP">日文</option>
            </select>
        </div>
        <button id="startRecordingBtn" class="btn success">开始录音</button>
        <button id="stopRecordingBtn" class="btn danger" disabled>停止录音</button>
        <button id="clearTextBtn" class="btn">清除文本</button>
        <div id="recordingStatus" class="status info">准备就绪</div>
    </div>

    <div class="card">
        <h2>识别结果</h2>
        <div id="recognitionResult" class="log">
            等待语音识别结果...
        </div>
        <div id="confidenceInfo" class="status info"></div>
    </div>

    <div class="card">
        <h2>调试信息</h2>
        <button id="clearLogBtn" class="btn">清除日志</button>
        <div id="debugLog" class="log"></div>
    </div>

    <script src="https://cdn.socket.io/4.7.2/socket.io.min.js"></script>
    <script>
        // 全局变量
        let socket = null;
        let mediaRecorder = null;
        let isRecording = false;
        let audioChunks = [];
        let recognition = null;

        // DOM 元素
        const connectionStatus = document.getElementById('connectionStatus');
        const deviceInfo = document.getElementById('deviceInfo');
        const connectBtn = document.getElementById('connectBtn');
        const disconnectBtn = document.getElementById('disconnectBtn');
        const startRecordingBtn = document.getElementById('startRecordingBtn');
        const stopRecordingBtn = document.getElementById('stopRecordingBtn');
        const clearTextBtn = document.getElementById('clearTextBtn');
        const recordingStatus = document.getElementById('recordingStatus');
        const recognitionResult = document.getElementById('recognitionResult');
        const confidenceInfo = document.getElementById('confidenceInfo');
        const debugLog = document.getElementById('debugLog');
        const clearLogBtn = document.getElementById('clearLogBtn');
        const recognitionMode = document.getElementById('recognitionMode');
        const language = document.getElementById('language');

        // 日志函数
        function log(message, type = 'info') {
            const timestamp = new Date().toLocaleTimeString();
            const logEntry = `[${timestamp}] ${message}`;
            debugLog.innerHTML += logEntry + '\n';
            debugLog.scrollTop = debugLog.scrollHeight;
            console.log(logEntry);
        }

        function clearLog() {
            debugLog.innerHTML = '';
        }

        // 连接服务器
        function connectToServer() {
            log('正在连接服务器...');
            
            const serverUrl = window.location.protocol === 'https:' 
                ? 'wss://' + window.location.hostname + ':3001'
                : 'ws://' + window.location.hostname + ':3001';
            
            socket = io(serverUrl, {
                transports: ['websocket', 'polling'],
                timeout: 10000
            });

            socket.on('connect', () => {
                log('✅ 连接成功，Socket ID: ' + socket.id);
                connectionStatus.textContent = '已连接';
                connectionStatus.className = 'status success';
                
                // 注册设备
                registerDevice();
            });

            socket.on('disconnect', (reason) => {
                log('❌ 连接断开: ' + reason);
                connectionStatus.textContent = '连接断开';
                connectionStatus.className = 'status error';
                updateRecordingButtons(false);
            });

            socket.on('connect_error', (error) => {
                log('❌ 连接错误: ' + error.message);
                connectionStatus.textContent = '连接失败';
                connectionStatus.className = 'status error';
            });

            // 监听语音识别结果
            socket.on('voice:result', (data) => {
                log('📥 收到语音识别结果: ' + JSON.stringify(data));
                
                if (data.success) {
                    recognitionResult.textContent = data.text || '无识别文本';
                    confidenceInfo.textContent = `置信度: ${Math.round((data.confidence || 0) * 100)}%`;
                    confidenceInfo.className = 'status success';
                    recordingStatus.textContent = '识别完成';
                    recordingStatus.className = 'status success';
                } else {
                    recognitionResult.textContent = '识别失败: ' + (data.error || '未知错误');
                    confidenceInfo.textContent = '';
                    confidenceInfo.className = 'status error';
                    recordingStatus.textContent = '识别失败';
                    recordingStatus.className = 'status error';
                }
                
                updateRecordingButtons(false);
            });

            socket.on('voice:error', (data) => {
                log('❌ 语音识别错误: ' + data.message);
                recordingStatus.textContent = '识别错误: ' + data.message;
                recordingStatus.className = 'status error';
                updateRecordingButtons(false);
            });

            // 监听配对结果
            socket.on('device:pair:result', (data) => {
                log('📱 配对结果: ' + JSON.stringify(data));
                if (data.success) {
                    deviceInfo.textContent = `已配对设备: ${data.deviceName || data.deviceId}`;
                    deviceInfo.className = 'status success';
                } else {
                    deviceInfo.textContent = '配对失败: ' + (data.error || '未知错误');
                    deviceInfo.className = 'status error';
                }
            });

            // 监听所有事件用于调试
            socket.onAny((eventName, ...args) => {
                log(`🔍 收到事件: ${eventName}`, 'debug');
            });
        }

        // 注册设备
        function registerDevice() {
            if (!socket) return;
            
            const deviceInfo = {
                type: 'mobile',
                name: 'Test Mobile Device',
                capabilities: {
                    canSendVoice: true,
                    canReceiveText: false,
                    canGenerateQR: false,
                    canScanQR: true,
                    speechRecognition: true,
                    mediaRecording: true,
                    camera: true,
                    vibration: true
                }
            };

            log('📱 注册设备: ' + JSON.stringify(deviceInfo));
            socket.emit('device:register', deviceInfo);
        }

        // 开始录音
        async function startRecording() {
            if (isRecording) return;
            
            try {
                log('🎤 开始录音...');
                
                const stream = await navigator.mediaDevices.getUserMedia({ 
                    audio: {
                        echoCancellation: true,
                        noiseSuppression: true,
                        autoGainControl: true,
                        sampleRate: 16000
                    } 
                });
                
                const mode = recognitionMode.value;
                const lang = language.value;
                
                if (mode === 'server') {
                    // 服务端识别模式
                    mediaRecorder = new MediaRecorder(stream, {
                        mimeType: 'audio/webm;codecs=opus'
                    });
                    
                    audioChunks = [];
                    
                    mediaRecorder.ondataavailable = (event) => {
                        if (event.data.size > 0) {
                            audioChunks.push(event.data);
                        }
                    };
                    
                    mediaRecorder.onstop = async () => {
                        log('🎤 录音结束，准备发送到服务端...');
                        const audioBlob = new Blob(audioChunks, { type: 'audio/webm;codecs=opus' });
                        
                        // 转换为base64
                        const reader = new FileReader();
                        reader.onload = () => {
                            const base64Data = reader.result;
                            log('📤 发送音频数据到服务端...');
                            
                            socket.emit('voice:recognize', {
                                audioData: base64Data,
                                language: lang,
                                timestamp: Date.now(),
                                options: {
                                    provider: 'baidu',
                                    format: 'webm'
                                }
                            });
                        };
                        reader.readAsDataURL(audioBlob);
                    };
                    
                    mediaRecorder.start();
                    
                } else {
                    // 客户端识别模式
                    if ('webkitSpeechRecognition' in window || 'SpeechRecognition' in window) {
                        const SpeechRecognition = window.SpeechRecognition || window.webkitSpeechRecognition;
                        recognition = new SpeechRecognition();
                        
                        recognition.continuous = false;
                        recognition.interimResults = true;
                        recognition.lang = lang;
                        
                        recognition.onresult = (event) => {
                            let finalTranscript = '';
                            let interimTranscript = '';
                            
                            for (let i = event.resultIndex; i < event.results.length; i++) {
                                const transcript = event.results[i][0].transcript;
                                if (event.results[i].isFinal) {
                                    finalTranscript += transcript;
                                } else {
                                    interimTranscript += transcript;
                                }
                            }
                            
                            recognitionResult.textContent = finalTranscript || interimTranscript;
                            
                            if (finalTranscript) {
                                log('✅ 客户端识别完成: ' + finalTranscript);
                                recordingStatus.textContent = '识别完成';
                                recordingStatus.className = 'status success';
                                updateRecordingButtons(false);
                            }
                        };
                        
                        recognition.onerror = (event) => {
                            log('❌ 客户端识别错误: ' + event.error);
                            recordingStatus.textContent = '识别错误: ' + event.error;
                            recordingStatus.className = 'status error';
                            updateRecordingButtons(false);
                        };
                        
                        recognition.onend = () => {
                            log('🎤 客户端识别结束');
                            updateRecordingButtons(false);
                        };
                        
                        recognition.start();
                    } else {
                        throw new Error('浏览器不支持语音识别');
                    }
                }
                
                isRecording = true;
                recordingStatus.textContent = '正在录音...';
                recordingStatus.className = 'status info recording';
                updateRecordingButtons(true);
                
            } catch (error) {
                log('❌ 开始录音失败: ' + error.message);
                recordingStatus.textContent = '录音失败: ' + error.message;
                recordingStatus.className = 'status error';
            }
        }

        // 停止录音
        function stopRecording() {
            if (!isRecording) return;
            
            log('🛑 停止录音...');
            
            if (mediaRecorder && mediaRecorder.state === 'recording') {
                mediaRecorder.stop();
            }
            
            if (recognition) {
                recognition.stop();
            }
            
            isRecording = false;
            recordingStatus.textContent = '处理中...';
            recordingStatus.className = 'status info';
        }

        // 更新录音按钮状态
        function updateRecordingButtons(recording) {
            startRecordingBtn.disabled = recording;
            stopRecordingBtn.disabled = !recording;
        }

        // 清除文本
        function clearText() {
            recognitionResult.textContent = '等待语音识别结果...';
            confidenceInfo.textContent = '';
            confidenceInfo.className = 'status info';
            recordingStatus.textContent = '准备就绪';
            recordingStatus.className = 'status info';
        }

        // 事件监听器
        connectBtn.addEventListener('click', connectToServer);
        disconnectBtn.addEventListener('click', () => {
            if (socket) {
                socket.disconnect();
                socket = null;
            }
        });
        startRecordingBtn.addEventListener('click', startRecording);
        stopRecordingBtn.addEventListener('click', stopRecording);
        clearTextBtn.addEventListener('click', clearText);
        clearLogBtn.addEventListener('click', clearLog);

        // 页面加载时自动连接
        window.addEventListener('load', () => {
            log('页面加载完成，准备连接服务器...');
            connectToServer();
        });

        // 页面卸载时清理
        window.addEventListener('beforeunload', () => {
            if (socket) {
                socket.disconnect();
            }
        });
    </script>
</body>
</html> 